<?php
//------------------------------------------------------------------------ Check that a folder was passed in
if ($_SERVER["argv"][1]==""){die("No Folder set");}
echo "Using ".$_SERVER["argv"][1]." folder\n";
$config["modulefolder"]=$_SERVER["argv"][1];
// win or nix
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    $config["win"]=1;
} else {
    $config["win"]=0;
}


//windows services
if($config["win"]==1){
	$SERVICE_NAME="xAPEngine".$config["modulefolder"];
	if($_SERVER["argv"][2]=="run"){
		if (!win32_start_service_ctrl_dispatcher($SERVICE_NAME)) die('Could not connect to service :'.$SERVICE_NAME);
		win32_set_service_status(WIN32_SERVICE_RUNNING);
	}
	if($_SERVER["argv"][2]=="install"){
		$x = win32_create_service(array(
        'service' => $SERVICE_NAME,
        'display' => 'xAP Engine '.$config["modulefolder"],
        'params' =>  ' -c c:\\xAP\\apache\\bin\\ -q c:\\xAP\\engine\\engine.php  '.$config["modulefolder"].' run',
		'path' => 'c:\\xAP\\apache\\bin\\php.exe'));
		win32_start_service($SERVICE_NAME);
		die("Service Added");
	}
	if($_SERVER["argv"][2]=="uninstall"){
		win32_stop_service($SERVICE_NAME);
		win32_delete_service($SERVICE_NAME);
		die("Service Removed");
	}
}

//------------------------------------------------------------------------ Get Includes
include_once "xAP-functions/functions.php";	// General functions
include_once "xAP-config/config.php"; // base $config details.
include_once $config["modulefolder"]."/config.php"; // module $config details. loaded last as can overwrite main config
include_once "xAP-functions/xAP.php";	// xAP functions
include_once "xAP-functions/database.php"; // all db access goes through here
include_once "xAP-functions/timer.php"; // functions that are called by the main loop every second ish
include_once "xAP-functions/event.php"; // functions that process an event
include_once "xAP-functions/xAPIncoming.php"; // handles receiving of xAP and the processing of messages
include_once "xAP-functions/databasesetup.php"; // checks the database has all the right fields/tables
//------------------------------------------------------------------------
//log PID
$fp = fopen ($config["basefolder"]."/engine/".$config["modulefolder"]."/pid", "w");
fwrite($fp, getmypid());
fclose($fp);





//------------------------------------------------------------------------ Get extra message handlers
$xAPFunctions = opendir($config["basefolder"]."/engine/".$config["modulefolder"]);
while($entryName = readdir($xAPFunctions)) {
	if (substr($entryName,0,12)=="xAPIncoming-"){
		include_once $config["modulefolder"]."/$entryName";
		xAPLog("xAP","Loaded ".$entryName,"");
	}
}
if (isset($config["include"])){ //  include  any other files.
	foreach($config["include"] as $value){
		include_once $config["modulefolder"]."/$value";
	}
}

//



//------------------------------------------------------------------------


//------------------------------------------------------------------------ Things to run at startup
DatabaseSetup(); // check the main tables
if (isset($config["dbsetup"])){ //  some incoming files may have requested db setups too
	foreach($config["dbsetup"] as $value){
		$value();
	}
}
if (isset($config["menu"])){
	DatabaseSaveMenu();
}
if (isset($config["widget"])){ //  register widgets
	foreach($config["widget"] as $value){
		RegisterWidget($value["title"],$value["url"],$value["urlconfig"]);
	}
}
if (isset($config["startup"])){ //  some file may request functions to be called at startup.
	foreach($config["startup"] as $value){
		xAPLog("xAP","Startup Function ".$value,"");
		$value();
	}
}




//------------------------------------------------------------------------   Setup Socket
set_time_limit(0);  //run forever
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($sock,$config["bindaddress"],0);
// setup the socket options
socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, TRUE);
socket_set_block($sock);
socket_set_option($sock,
                         SOL_SOCKET,
                         SO_RCVTIMEO,
                         array("sec"=>1,"usec"=>0));
					 
//store cofnig of socket as we'll need it in teh hbeats
socket_getsockname($sock, $IP, $PORT);
$config["xapport"]=$PORT;
$config["xapip"]=$IP;

//------------------------------------------------------------------------  Main Loop
$lasthbeat=0; //used to trigger the hbeats every xaphbeatinterval s
$lasttimer=0; //used to check for the one second timer
//loop forever
while(1){
	// check buffer
	if (($len = @socket_recvfrom($sock,$ret,2000,MSG_WAITALL,$cIP,$cPort)) != false) {

		@xAPProcessIncoming($ret,$cIP,$cPort);
	}
	//heartbeat?
	if(time()-$lasthbeat>$config["xaphbeatinterval"]){
		@xAPSendHeartBeat();
		$lasthbeat=time();
	}
	if(time()!=$lasttimer){
		@TimerOneSecond();
		$lasttimer=time();
		//terminate
		if(file_exists($config["basefolder"]."/tmp/kill_".$config["modulefolder"])){
			unlink($config["basefolder"]."/tmp/kill_".$config["modulefolder"]);
			xAPLog("xAP","Shutting down","");
			die();
		}
		// service callback
		if($config["win"]==1 && $_SERVER["argv"][2]=="run"){
			NTServiceResponder();
		}
	}
}


// never really going to get here but why no!
socket_set_nonblock($sock);
socket_close($sock);


function NTServiceResponder()
{

    switch (win32_get_last_control_message())
    {
    case 0: // PATCH for: seems never to go to 4 (WIN32_SERVICE_CONTROL_INTERROGATE)
        win32_set_service_status(WIN32_SERVICE_RUNNING);
        return TRUE;
        break;
    case WIN32_SERVICE_CONTROL_CONTINUE:
        return TRUE; // "Continue"
    case WIN32_SERVICE_CONTROL_INTERROGATE:
        win32_set_service_status(WIN32_SERVICE_RUNNING);
        return TRUE; // Respond with status
    case WIN32_SERVICE_CONTROL_STOP:
        win32_set_service_status(WIN32_SERVICE_STOPPED);
        exit; // Terminate script
    default:
        win32_set_service_status(WIN32_ERROR_CALL_NOT_IMPLEMENTED); // Add more cases to handle other service calls
    }

    return FALSE;
}
?>